#include "Buffer.h"
#include "Logger.h"

#include <sys/uio.h>
#include <unistd.h>

/**
 * 从fd上读取数据，epoll工作在LT模式
 * Buffer的缓冲区有大小，但从fd读数据时，因为时字节流，无法得知tcp数据的最终大小
 */
ssize_t Buffer::readFd(int fd, int *savedErrno)
{
    const size_t writable = writableBytes();

    char extrabuf[65536]={0}; // 开辟在栈上的内存空间

    struct iovec vec[2];
    vec[0].iov_base = beginWrite();
    vec[0].iov_len = writable;
    vec[1].iov_base = extrabuf;
    vec[1].iov_len = sizeof(extrabuf);

    const int iovcnt = (writable < sizeof(extrabuf)) ? 2 : 1; // 一开始肯定小于，但随着append，会扩容，以后可能大于
    const ssize_t n = readv(fd, vec, iovcnt);                     // 从fd中读取数据直接写到缓冲区中，放不下的放入extrbuf
    if (n < 0)
    {
        *savedErrno = errno;
    }
    else if (n <= writable) // 能放下，extrabuf中没有数据
    {
        writerIndex_ += n;
    }
    else
    {
        writerIndex_ = buffer_.size();
        append(extrabuf, n - writable);
    }
    return n;
}

ssize_t Buffer::writeFd(int fd, int *savedErrno)
{
    ssize_t n = write(fd, peek(), readableBytes());
    if (n < 0)
    {
        *savedErrno = errno;
    }
    else
    {
        retrieve(n);
    }
    return n;
}


//为了调试
std::string Buffer::output()
{
    std::string result(peek(), readableBytes());
    return result;
}